/* 
 * Copyright 2009 Michal Trzcinka
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 * 
 */

YAHOO.namespace('TRZCINKA.VCARD');

(function() {

  //noinspection JSDeprecatedSymbols
  var Dom = YAHOO.util.Dom,
      Lang = YAHOO.lang,
      DD = YAHOO.util.DD,
      DDProxy = YAHOO.util.DDProxy,
      DDM = YAHOO.util.DragDropMgr,
      DDTarget = YAHOO.util.DDTarget,
      ContextMenu = YAHOO.widget.ContextMenu,
      Element = YAHOO.util.Element,
      Event = YAHOO.util.Event,
      Constants = YAHOO.TRZCINKA.VCARD.Constants,
      Config = YAHOO.TRZCINKA.VCARD.Config,
      JSON = YAHOO.lang.JSON,
      Tooltip = YAHOO.widget.Tooltip,
      LOGGER = new YAHOO.widget.LogWriter('view.js');

  LOGGER.log('Initializing TRZCINKA.VCARD.GridView module...', 'info');

  /**
   * Cells
   */

  YAHOO.TRZCINKA.VCARD.Cells = function() {
    var cells = [];

    this.getCell = function(location) {
      return cells.find(function(cell) {
        return cell.location.equals(location);
      });
    };

    this.putCell = function(cell) {
      cells.push(cell);
    };
  };

  var Cells = YAHOO.TRZCINKA.VCARD.Cells;


  /**
   * Item
   */

  YAHOO.TRZCINKA.VCARD.Item = function(gridModel, cells, cell, existingItem) {
    var that = this;

    this.htmlElement = document.createElement('div');
    Dom.addClass(this.htmlElement, 'cell');
    Dom.setStyle(this.htmlElement, 'width', (Config.cellWidth - 20) + 'px');
    Dom.setStyle(this.htmlElement, 'height', (Config.cellHeight - 20) + 'px');
    Dom.setStyle(this.htmlElement, 'backgroundColor', 'white');
    var textarea = null;

    if (existingItem) {
      applyEventHandlers();
      this.htmlElement.innerHTML = existingItem.getContent();
    } else {
      editMode();
    }

    this.getContent = function() {
      return textarea ? textarea.value : that.htmlElement.innerHTML;
    };

    this.setContent = function(content) {
      if (textarea) {
        textarea.value = content;
      } else {
        that.htmlElement.innerHTML = content;
      }
    };

    function editMode() {
      LOGGER.log('entering edit mode in ' + Lang.dump(cell), 'debug');
      Event.purgeElement(that.htmlElement, false, 'click');
      textarea = document.createElement('textarea');
      var TEXTAREA_ID = Dom.generateId();
      textarea.id = TEXTAREA_ID;
      textarea.value = that.htmlElement.innerHTML;
      that.htmlElement.innerHTML = '';
      Event.onContentReady(TEXTAREA_ID, function(textarea) {
        textarea.focus();
      }, textarea);

      Dom.setStyle(textarea, 'width', (Config.cellWidth - 20) + 'px');
      Dom.setStyle(textarea, 'height', (Config.cellHeight - 20) + 'px');
      Dom.addClass(textarea, 'cell');
      Event.addBlurListener(textarea, function() {
        viewMode();
      });
      that.htmlElement.appendChild(textarea);
    }

    function applyEventHandlers() {
      Event.on(that.htmlElement, 'click', function() {
        editMode();
      });
      Event.on(that.htmlElement, 'mouseover', function() {
      });
      Event.on(that.htmlElement, 'mouseout', function() {
      });
    }

    function viewMode() {
      LOGGER.log('entering view mode in ' + Lang.dump(cell), 'debug');
      gridModel.updateItem(cell.location, textarea.value);
      var content = textarea.value;
      that.htmlElement.removeChild(textarea);
      that.htmlElement.innerHTML = content;
      Event.purgeElement(textarea);
      applyEventHandlers();
      textarea = null;
      var anotherTAs = document.getElementsByTagName('textarea'); //workaround to set focus properly
      if (anotherTAs.length > 0) {
        anotherTAs[0].focus();
      }
    }

    //dd
    YAHOO.TRZCINKA.VCARD.DDPlayer = function(id, sGroup, config) {
      YAHOO.TRZCINKA.VCARD.DDPlayer.superclass.constructor.apply(this, arguments);
      this.initConstraints(config.regionId);
      this.initPlayer(id, sGroup, config);
    };

    YAHOO.extend(YAHOO.TRZCINKA.VCARD.DDPlayer, DDProxy, {
      initConstraints: function(regionId) {
        var region = Dom.getRegion(regionId);
        var el = this.getEl();

        Event.onContentReady(el.id, function() {
          var xy = Dom.getXY(el);

          var width = parseInt(Dom.getStyle(el, 'width'), 10);
          var height = parseInt(Dom.getStyle(el, 'height'), 10);

          var left = xy[0] - region.left;
          var right = region.right - xy[0] - width;
          var top = xy[1] - region.top;
          var bottom = region.bottom - xy[1] - height;

          this.setXConstraint(left, right);
          this.setYConstraint(top, bottom);
        }, this, true);

      },

      initPlayer: function(id, sGroup, config) {
        this.startPos = Dom.getXY(this.getEl());
        this.isTarget = false;
        this.startCell = cell;
      },
      onDragDrop: function(e, id) {
        LOGGER.log('drag drop on ' + id);
        var oldLocation = this.startCell.location;
        var newLocation = id.fromGridLocation();
        if (oldLocation.equals(newLocation)) {
          Dom.setXY(this.getEl(), this.startPos);
        } else {
          gridModel.moveItem(oldLocation, newLocation);
          this.startCell.moveItem(cells.getCell(newLocation));
          this.startPos = Dom.getXY(this.getEl());
        }
      },

      onInvalidDrop: function() {
        LOGGER.log('invalid drop');
        Dom.setXY(this.getEl(), this.startPos);
      } ,

      endDrag: function() {
      }

    });

    var dd = new YAHOO.TRZCINKA.VCARD.DDPlayer(this.htmlElement, Constants.DD_GROUP, {regionId: Constants.TABLE_ID});

    this.destroy = function() {
      dd.unreg();
      Event.purgeElement(this.htmlElement, true);
    };

  };

  var Item = YAHOO.TRZCINKA.VCARD.Item;

  /**
   * Cell
   */

  YAHOO.TRZCINKA.VCARD.Cell = function(location, gridModel, cells) {
    this.location = location;
    this.item = null;

    this.htmlElement = document.createElement('td');
    Dom.setStyle(this.htmlElement, 'width', Config.cellWidth + 'px');
    this.htmlElement.id = location.gridLocationToString();

    var ddTarget = new DDTarget(this.htmlElement.id, Constants.DD_GROUP);

    this.createItem = function(existingItem) {
      if (existingItem) {
        this.item = new Item(gridModel, cells, this, existingItem);
      } else {
        this.item = new Item(gridModel, cells, this);
      }
      this.htmlElement.appendChild(this.item.htmlElement);
    };

    this.removeItem = function() {
      this.htmlElement.removeChild(this.item.htmlElement);
      this.item.destroy();
      this.item = null;
    };

    this.moveItem = function(targetCell) {
      if (targetCell.item) { //swap
        var itemA = this.item;
        var itemB = targetCell.item;
        this.removeItem();
        targetCell.removeItem();
        this.createItem(itemB);
        targetCell.createItem(itemA);
      } else {
        targetCell.createItem(this.item);
        this.removeItem();
      }
    };

  };

  YAHOO.TRZCINKA.VCARD.Cell.prototype.toString = function() {
    return Lang.dump(this.location);
  };

  var Cell = YAHOO.TRZCINKA.VCARD.Cell;

  /**
   * GridContextMenu
   */

  YAHOO.TRZCINKA.VCARD.buildContextMenu = function(cells, tableId, gridModel) {
    var createItem = {text: 'Create item', onclick: {fn: function(eventName, event, location) {
      var cell = cells.getCell(location);
      cell.createItem();
      gridModel.createItem(location);
    }}};
    var removeItem = {text: 'Remove item', onclick: {fn: function(eventName, event, location) {
      var cell = cells.getCell(location);
      cell.removeItem();
      gridModel.removeItem(location);
    }}};
    var ctxMenu = new ContextMenu(Dom.generateId(), {trigger: tableId, lazyload: true, itemdata: [createItem]});
    ctxMenu.subscribe('beforeShow', function() {
      this.clearContent();
      var cell;
      if (this.contextEventTarget.tagName == 'TD') {
        cell = this.contextEventTarget;
      } else {
        cell = Dom.getAncestorByTagName(this.contextEventTarget, 'TD');
      }
      var location = cell.id.fromGridLocation();
      if (!gridModel.itemExists(location)) {
        createItem.onclick.obj = location;
        this.addItem(createItem); //add 'create' option to the menu
      } else {
        removeItem.onclick.obj = location;
        this.addItem(removeItem); //add 'remove' option to the menu
      }
      this.render();
    });
  };

  var buildContextMenu = YAHOO.TRZCINKA.VCARD.buildContextMenu;


  /**
   * GridView
   */

  YAHOO.TRZCINKA.VCARD.GridView = function(parent, gridModel) {
    LOGGER.log('instantiating GridView', 'debug');

    var onGridModelChange = function(type, args) {
      var gridData = args[0];
      LOGGER.log('View received event on model change: type ' + type + ', eventData: ' + JSON.stringify(gridData), 'debug');

      if (type == Constants.MODEL_LOADED_EVENT) {

        LOGGER.log('View building grid view because of gridLoaded event received', 'debug');
        cells = new Cells();

        var table = document.createElement('table');
        table.id = Constants.TABLE_ID;
        Dom.addClass(table, 'grid');
        Dom.setStyle(table, 'width', (Config.cellWidth * gridData.columns) + 'px');
        Dom.setStyle(table, 'height', (Config.cellHeight * gridData.rows) + 'px');

        for (var y = 0; y < gridData.rows; y++) {
          var row = document.createElement('tr');
          for (var x = 0; x < gridData.columns; x++) {
            var cell = new Cell({row: y, column: x}, gridModel, cells);
            row.appendChild(cell.htmlElement);
            cells.putCell(cell);
          }
          Dom.setStyle(row, 'height', Config.cellHeight + 'px');
          table.appendChild(row);
        }

        parent.appendChild(table);

        buildContextMenu(cells, table.id, gridModel);

        if (gridData.items) {
          for (var i = 0; i < gridData.items.length; i++) {
            var itemData = gridData.items[i];
            cell = cells.getCell(itemData.location);
            var item = new Item(gridModel, cells, cell);
            item.setContent(itemData.text);
            cell.createItem(item);
          }
        }
      }

    };

    gridModel.gridModelEvent.subscribe(onGridModelChange);

    var cells = null;

  };


})();
